<?php

use support\Request;
use support\Response;
use think\Container;

function root_path()
{
    return ROOT_PATH;
}

function base_path()
{
    return root_path();
}

function config_path()
{
    return root_path() . DIRECTORY_SEPARATOR . 'config';
}

function runtime_path()
{
    return root_path() . DIRECTORY_SEPARATOR . 'runtime';
}

function storage_path()
{
    return runtime_path() . DIRECTORY_SEPARATOR . 'storage';
}

function env($key = null, $default = null)
{
    return envs($key, $default);
}

/**
 * envs环境参数获取
 * @param $key
 * @param null $default
 * @return mixed|null
 */
function envs($key = null, $default = null)
{
    static $env_config;
    if (!$env_config) {
        $env_config = env_load();
    }
    if ($key == null) {
        return $default;
    }
    $key = strtoupper(str_replace('.', '_', $key));
    return $env_config[$key] ?? $default;
}

function env_load(string $env = '')
{
    $res = [];
    $file = base_path() . DIRECTORY_SEPARATOR . '.env' . ($env ? '.' . $env : '');
    if (file_exists($file) == FALSE) {
        return $res;
    }
    try {
        $temp = parse_ini_file($file, true);
        $temp = array_change_key_case($temp, CASE_UPPER);
    } catch (\Exception $e) {
        return  $res;
    }
    foreach ($temp as $key => $val) {
        if (is_array($val)) {
            foreach ($val as $k => $v) {
                $res[$key . '_' . strtoupper($k)] = $v;
            }
        } else {
            $res[$key] = $val;
        }
    }
    return $res;
}

function config(string $key = '', string |int | array |null $default = null)
{
    static $config = [];
    static $config_loaded = false;
    if (!$config_loaded) {
        $config = config_load($key, $default);
        $config_loaded = true;
    }
    $keyArray = explode('.', $key);
    $value = $config;
    foreach ($keyArray as $index) {
        if (!isset($value[$index])) {
            return $default;
        }
        $value = $value[$index];
    }
    return $value;
}

function config_load(string $key = '')
{
    return getPhpArraysFromDirectory(config_path());
}

/**
 * 读取目录及子目录下所有PHP文件，并合并其返回的数组
 *
 * @param string $directory 要扫描的起始目录
 * @return array 合并后的所有数组结果
 */
function getPhpArraysFromDirectory($directory)
{
    $combinedArray = [];

    // 检查目录是否存在且可读
    if (!is_dir($directory) || !is_readable($directory)) {
        return [];
    }

    // 创建递归迭代器来遍历所有文件和子目录
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS),
        RecursiveIteratorIterator::LEAVES_ONLY // 只遍历文件，忽略目录本身
    );

    // 过滤出.php文件
    $phpFiles = new RegexIterator($iterator, '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH);

    foreach ($phpFiles as $file) {
        $filePath = $file[0]; // RegexIterator返回的是匹配数组
        $content = getArrayFromPhpFile($filePath);
        $pathStr = str_replace($directory . PATH_SEPARATOR, '', $filePath);
        $pathArray = explode(PATH_SEPARATOR, $pathStr);
        if (!empty($pathArray)) {
            $lastIndex = count($pathArray) - 1;
            $pathArray[$lastIndex] = pathinfo($pathArray[$lastIndex], PATHINFO_FILENAME);
        }
        $res = arr2tree($pathArray, $content);
        $combinedArray = array_merge_recursive($combinedArray, $res);
    }

    return $combinedArray;
}

/**
 * 安全地从PHP文件获取return数组的内容
 * 使用输出缓冲来捕获可能产生的错误或意外输出
 *
 * @param string $filePath PHP文件的完整路径
 * @return array 返回数组，失败返回空数组
 */
function getArrayFromPhpFile($filePath)
{
    // 使用输出缓冲，防止文件中有意外的echo等输出
    ob_start();

    // 使用@抑制可能出现的警告
    $result = @include $filePath;

    // 获取缓冲内容并清空缓冲区
    $output = ob_get_clean();

    // 如果文件有输出或者返回值不是数组，则视为无效
    if (!empty($output) || !is_array($result)) {
        return [];
    }
    return $result;
}

function arr2tree(array $keys, $value = null)
{
    $res = $value;
    for ($i = count($keys) - 1; $i >= 0; $i--) {
        $res = [$keys[$i] => $res];
    }
    return $res;
}

function app($name, $param = [])
{
    $container = Container::getInstance();
    if ($container->has($name)) {
        return $container->get($name);
    }

    return $container->make($name, $param);
}

function request()
{
    return app(Request::class);
}

function response()
{
    return new Response();
}

function handle($handler, $vars)
{
    [$className, $methodName] = explode('/', $handler);
    $constructorArgs = [];

    $className = str_replace(['/', '.'], '\\', $className);
    $classReflection = new ReflectionClass($className);
    $instance = $classReflection->newInstanceArgs($constructorArgs);
    $methodReflection = $classReflection->getMethod($methodName);
    $methodParams = $methodReflection->getParameters();
    $args = [];
    $vars['request'] = request();
    foreach ($methodParams as $param) {
        $paramName = $param->getName();
        if (array_key_exists($paramName, $vars)) { // 检查 $vars 中是否存在对应参数名的键
            $args[] = $vars[$paramName];
        } elseif ($param->isDefaultValueAvailable()) {
            $args[] = $param->getDefaultValue();
        } else {
            throw new InvalidArgumentException("Missing required parameter '$paramName' for method '$methodName' in class '$className'.");
        }
    }
    return $methodReflection->invokeArgs($instance, $args);
}

function dispatch($app, $controller, $act)
{
    $handler = 'app\\' . $app . '\\controller\\' . $controller . 'Controller/' . $act;
    return handle($handler, request()->get());
}

function view()
{

}
function json($data)
{
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($data, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
}

function success($data)
{

    return json([
        'code' => 0,
        'status' => 'success',
        'data' => $data,
    ]);
}

function fail($code, $message = '')
{
    return json([
        'code' => $code,
        'status' => 'error',
        'message' => $message ?: 'Unknown Error',
    ]);
}